#include <math.h>
#include "Node.h"

#ifdef SYPX_MEMCHECK
#include "mmgr.h"
#endif

#include "Instance.h"
#include "WolfInstance.h"
#include "Wolf.h"
#include "Graph.h"
#include "Level.h"

namespace SheepDefence
{
	Node::Node()
	{
	}

	Node::~Node()
	{
	}

	void Node::init(float x, float y, Graph* g)
	{
		owner = g;
		this->x = x;
		this->y = y;
	}

	void Node::addNeighbour(Node* neighbour)
	{
		std::pair<Node*, float> newNeighbour;
		
		newNeighbour.first = neighbour;
		newNeighbour.second = 0;
		
		neighbours.push_back(newNeighbour);
	}

	void Node::update()
	{
		std::vector< std::pair<Node*, float> >::iterator i = neighbours.begin();

		while (i != neighbours.end())
		{
			i->second = sqrt(Instance::getDist(i->first->x - x, i->first->y - y));
			i++;
		}
	}

	void Node::reset()
	{
		point = -1;
	}

	void Node::sharedReset()
	{
		shared = -1;
		sharedHungry = -1;
	}

	void Node::addOrigin(float x, float y, std::vector<ObstacleInstance*>& obstacles, float size)
	{
		std::vector<ObstacleInstance*> blank;

		addOrigin(x, y, obstacles, size, blank);
	}

	void Node::addOrigin(float x, float y, std::vector<ObstacleInstance*>& obstacles, float size, std::vector<ObstacleInstance*>& exceptions)
	{
		float dist = sqrt(Instance::getDist(this->x - x, this->y - y));

		if (point == -1 || point > dist)
			if (!Instance::collision(this->x, this->y, x, y, obstacles, size, exceptions))
				point = dist;
	}

	void Node::addOrigin(float x, float y, std::vector<ObstacleInstance*>& obstacles, WolfInstance* wolf, DogInstance* dog)
	{
		float dist = sqrt(Instance::getDist(this->x - x, this->y - y));

		if (point == -1 || point > dist)
			if (!Instance::collision(this->x, this->y, x, y, obstacles, wolf, dog))
				point = dist;
	}

	void Node::addSharedOrigin(float x, float y, std::vector<ObstacleInstance*>& obstacles, WolfInstance* wolf, DogInstance* dog)
	{
		float dist = sqrt(Instance::getDist(this->x - x, this->y - y));

		if (shared == -1 || shared > dist)
			if (!Instance::collision(this->x, this->y, x, y, obstacles, wolf, dog))
				shared = dist;

		if (sharedHungry == -1 || sharedHungry > dist)
			if (!Instance::collision(this->x, this->y, x, y, obstacles, wolf->actor->collision))
				sharedHungry = dist;
	}

	bool Node::calculate()
	{
		std::vector< std::pair<Node*, float> >::iterator i = neighbours.begin();
		bool change = false;

		while (i != neighbours.end())
		{
			float new_point = (*i).second + (*i).first->point;
			// MAGIC NUMBER
			if ((*i).first->point != -1 && (point == -1 || new_point < point))
			{
				point = new_point;
				change = true;
			}

			i++;
		}

		return change;
	}

	bool Node::calculate(WolfInstance* wolf, DogInstance* dog)
	{		
		std::vector<ObstacleInstance*> empty_obstacles;
		std::vector<std::pair<Node*, float> >::iterator i = neighbours.begin();
		bool change = false;

		while (i != neighbours.end())
		{
			float new_point = (*i).second + (*i).first->point;
			if ((*i).first->point != -1 && (point == -1 ||  new_point < point)  && (Instance::getDist(dog->x, dog->y, x, y, (*i).first->x, (*i).first->y) > pow(dog->actor->fear + wolf->actor->fear, 2)))
			{
				point = new_point;
				change = true;
			}

			i++;
		}

		return change;
	}

	bool Node::calculateShared(WolfInstance* wolf, DogInstance* dog)
	{		
		std::vector<ObstacleInstance*> empty_obstacles;
		std::vector<std::pair<Node*, float> >::iterator i = neighbours.begin();
		bool change = false;

		while (i != neighbours.end())
		{
			float new_shared = (*i).second + (*i).first->shared;
			if ((*i).first->shared != -1 && (shared == -1 ||  new_shared < shared) && (!Instance::collision(x, y, (*i).first->x, (*i).first->y, empty_obstacles, wolf, dog)))
			{
				shared = new_shared;
				change = true;
			}

			i++;
		}

		i = neighbours.begin();

		while (i != neighbours.end())
		{
			float new_hungry = (*i).second + (*i).first->sharedHungry;
			if ((*i).first->sharedHungry != -1 && (sharedHungry == -1 ||  new_hungry < sharedHungry))
			{
				sharedHungry = new_hungry;
				change = true;
			}

			i++;
		}

		return change;
	}
}